package com.spzx.cart.service.impl;

import com.spzx.cart.service.CartService;
import com.spzx.common.core.constant.SecurityConstants;
import com.spzx.common.core.domain.R;
import com.spzx.common.core.exception.ServiceException;
import com.spzx.common.security.utils.SecurityUtils;
import com.spzx.product.api.RemoteProductService;
import com.spzx.product.api.vo.ProductSkuVo;
import com.spzx.product.api.vo.SkuPriceVo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import com.spzx.cart.api.domain.CartInfo;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author LOGIN
 * @title CartServiceImpl
 * @create 2025/7/25 22:45
 * @description
 */
@Service
public class CartServiceImpl implements CartService {

    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RemoteProductService remoteProductService;

    @Override
    public void addToCart(Long skuId, Integer skuNum) {
        //下面两行代码实现购物车功能中的用户身份识别和数据定位：
        //获取用户ID
        Long userId = SecurityUtils.getUserId();
        //生成购物车键名
        String cartKey = getCartKey(userId);
        //获取Redis中指定键的Hash操作对象，用于对购物车数据进行操作。
        BoundHashOperations<String,String, CartInfo> hashOps = redisTemplate.boundHashOps(cartKey);//第一个 String：Redis key 的类型（购物车键名） 第二个 String：Hash 中 field 的类型（SKU ID）  第三个 CartInfo：Hash 中 value 的类型（购物车商品信息）
        String hashKey = skuId.toString();
        int threshold = 99;
        if(hashOps.hasKey(hashKey)){
            //4.1 说明该商品在购物车中已有，对数量进行累加 ，不能超过指定上限99
            CartInfo cartInfo =hashOps.get(hashKey);
            int totalCount= cartInfo.getSkuNum()+skuNum;
            if (totalCount > threshold){
                throw new ServiceException("购物车商品数量超过上限");
            }
            cartInfo.setSkuNum(totalCount);
            hashOps.put(hashKey,cartInfo);
        }else {
            //3.判断购物车商品种类（不同SKU）总数大于50件
            Long count = hashOps.size();
            if (++count > 3){
                throw new ServiceException("购物车商品种类数量超过上限");
            }
            R<ProductSkuVo> productSkuResult = remoteProductService.getproductSku(skuId, SecurityConstants.INNER);
            if (R.FAIL == productSkuResult.getCode()){
                throw new ServiceException(productSkuResult.getMsg());
            }
            ProductSkuVo productSku = productSkuResult.getData();
            CartInfo cartInfo = new CartInfo();
            cartInfo.setSkuId(productSku.getId());
            cartInfo.setCartPrice(productSku.getSalePrice());
            cartInfo.setSkuNum(skuNum);
            cartInfo.setSkuPrice(productSku.getSalePrice());
            cartInfo.setThumbImg(productSku.getThumbImg());
            cartInfo.setSkuName(productSku.getSkuName());
            cartInfo.setCreateTime(new Date());
            //存储购物车数据
            hashOps.put(skuId.toString(),cartInfo);
        }


    }

    @Override
    public List<CartInfo> cartList() {
        //获取用户ID
        Long userId = SecurityUtils.getUserId();
        //生成购物车键名
        String cartKey = getCartKey(userId);
        //获取Redis中指定键的Hash操作对象，用于对购物车数据进行操作。
        BoundHashOperations<String,String, CartInfo> hashOps = redisTemplate.boundHashOps(cartKey);//第一个 String：Redis key 的类型（购物车键名） 第二个 String：Hash 中 field 的类型（SKU ID）  第三个 CartInfo：Hash 中 value 的类型（购物车商品信息）
        //获取hashOps中的所有数据
        List<CartInfo> cartInfoList = hashOps.values();
        //将数据按照时间倒叙显示
        cartInfoList = cartInfoList.stream().sorted((o1, o2) -> o2.getCreateTime().compareTo(o1.getCreateTime())).toList();
        //获取商品skuid列表
        List<Long> skuIdlist = cartInfoList.stream().map(CartInfo::getSkuId).toList();
        //获取购物车商品的实时价格
        R<List<SkuPriceVo>> skuPriceListResult = remoteProductService.getSkuPriceList(skuIdlist, SecurityConstants.INNER);
        if (R.FAIL == skuPriceListResult.getCode()){
            throw new ServiceException(skuPriceListResult.getMsg());
        }
        List<SkuPriceVo> skuPriceList = skuPriceListResult.getData();
        Map<Long, BigDecimal> priceMap = skuPriceList.stream().collect(Collectors.toMap(SkuPriceVo::getSkuId, SkuPriceVo::getSalePrice));//将 skuPriceList 转换为一个 Map，其中键是 SKU ID，值是对应的商品销售价格。
        for (CartInfo cartInfo : cartInfoList){
            Long skuId = cartInfo.getSkuId();
            //查找价格发生变化的商品
           if( cartInfo.getSkuPrice().compareTo(priceMap.get(skuId)) != 0){
               //设置最新的商品价格
               cartInfo.setSkuPrice(priceMap.get(skuId));
               //更新购物车中的价格
               hashOps.put(cartInfo.getSkuId().toString(),cartInfo);
           }
        }
        return cartInfoList;
    }

    @Override
    public void deleteCart(Long skuId) {
        String hashKey = skuId.toString();
        //获取用户ID
        Long userId = SecurityUtils.getUserId();
        //生成购物车键名
        String cartKey = getCartKey(userId);
        //获取Redis中指定键的Hash操作对象，用于对购物车数据进行操作。
        BoundHashOperations<String,String, CartInfo> hashOps = redisTemplate.boundHashOps(cartKey);//第一个 String：Redis key 的类型（购物车键名） 第二个 String：Hash 中 field 的类型（SKU ID）  第三个 CartInfo：Hash 中 value 的类型（购物车商品信息）
        hashOps.delete(hashKey);

    }

    @Override
    public void checkCart(Long skuId, Integer isChecked) {
        //获取用户ID
        Long userId = SecurityUtils.getUserId();
        //生成购物车键名
        String cartKey = getCartKey(userId);
        //获取Redis中指定键的Hash操作对象，用于对购物车数据进行操作。
        BoundHashOperations<String,String, CartInfo> hashOps = redisTemplate.boundHashOps(cartKey);//第一个 String：Redis key 的类型（购物车键名） 第二个 String：Hash 中 field 的类型（SKU ID）  第三个 CartInfo：Hash 中 value 的类型（购物车商品信息）
        String hashKey = skuId.toString();
        //先获取用户选择的商品
        if(hashOps.hasKey(skuId.toString())) {
            CartInfo cartInfoUpd = hashOps.get(hashKey);
            //cartInfoUpd写回缓存
            cartInfoUpd.setIsChecked(isChecked);
            //更新缓存
            hashOps.put(skuId.toString(),cartInfoUpd);

        }
    }

    @Override
    public void allCheckCart(Integer isChecked) {
        //获取用户ID
        Long userId = SecurityUtils.getUserId();
        //生成购物车键名
        String cartKey = getCartKey(userId);
        //获取Redis中指定键的Hash操作对象，用于对购物车数据进行操作。
        BoundHashOperations<String,String, CartInfo> hashOps = redisTemplate.boundHashOps(cartKey);//第一个 String：Redis key 的类型（购物车键名） 第二个 String：Hash 中 field 的类型（SKU ID）  第三个 CartInfo：Hash 中 value 的类型（购物车商品信息）

        //获取hashOps中的所有数据
        List<CartInfo> cartInfoList = hashOps.values();
        for (CartInfo item : cartInfoList) {
            CartInfo cartInfoUpd = hashOps.get(item.getSkuId().toString());
            //cartInfoUpd写回缓存
            cartInfoUpd.setIsChecked(isChecked);
            //更新缓存
            hashOps.put(item.getSkuId().toString(), cartInfoUpd);
        }


    }

    @Override
    public void clearCart() {
        //获取用户ID
        Long userId = SecurityUtils.getUserId();
        //生成购物车键名
        String cartKey = getCartKey(userId);
        //删除购物车键 名
        redisTemplate.delete(cartKey);

    }

    @Override
    public List<CartInfo> getCartCheckedList() {
        //获取购物车key
        Long userId = SecurityUtils.getUserId();
        String cartKey = getCartKey(userId);

        BoundHashOperations hashOperations = redisTemplate.boundHashOps(cartKey);//获取hashOperations时，就与cartKey绑定了
        List<CartInfo> CartInfoList = hashOperations.values();//获取数据列表
        CartInfoList = CartInfoList.stream().filter(cartInfo -> cartInfo.getIsChecked() == 1).toList();
        return CartInfoList;
    }

    @Override
    public Boolean deleteCartCheckedList() {

        Long userId = SecurityUtils.getUserId();
        String cartKey = getCartKey(userId);//获取购物车key
        BoundHashOperations hashOperations = redisTemplate.boundHashOps(cartKey);//获取hashOperations时，就与cartKey绑定了
        List<CartInfo> cartInfolist = hashOperations.values();
        cartInfolist
                .stream()
                .filter(cartInfo -> cartInfo.getIsChecked() == 1)//过滤出选中的购物车数据
                .forEach(cartInfo -> hashOperations.delete((cartInfo.getSkuId().toString())));//删除购物车数据
        return true;
    }

    //更新用户购物车列表价格
    @Override
    public Boolean updateCartPrice() {
        //获取购物车商品列表
        Long userId = SecurityUtils.getUserId();
        String cartKey = getCartKey(userId);//获取购物车的key
        BoundHashOperations<String,String, CartInfo> hashOps= redisTemplate.boundHashOps(cartKey);
        List<CartInfo> cartInfoList = hashOps.values();
        if (!CollectionUtils.isEmpty(cartInfoList)){
            //获取cartInfoList的skuId
            List<Long> skuIdList = cartInfoList.stream().map(CartInfo::getSkuId).toList();
            //获取商品的实时价格
            R<List<SkuPriceVo>> skuPriceVoListResult = remoteProductService.getSkuPriceList(skuIdList, SecurityConstants.INNER);
            if (R.FAIL == skuPriceVoListResult.getCode()){
                throw new ServiceException(skuPriceVoListResult.getMsg());
            }
            List<SkuPriceVo> skuPriceVoList = skuPriceVoListResult.getData();

            //将skuPriceVoList转换成map:  skuId做键，salePrice做值
            Map<Long, BigDecimal> skuPriceVoMap  = skuPriceVoList.stream().collect(Collectors.toMap(SkuPriceVo::getSkuId, SkuPriceVo::getSalePrice));

            //如果有变则更新购物车商品的价格
            for (CartInfo cartInfo:cartInfoList){
                Long skuId = cartInfo.getSkuId();
                BigDecimal price = skuPriceVoMap.get(skuId);
                if (cartInfo.getSkuPrice().compareTo(price) != 0){
                    cartInfo.setSkuPrice( price);
                    hashOps.put(skuId.toString(), cartInfo);
                }
            }
        }
        return true;

    }

    //根据用户ID生成一个唯一的 Redis 键名，用于存储该用户的购物车数据。
    private String getCartKey(Long userId){
        return "user:cart:"+userId;
    }
}
